<?php

namespace Biz\service\wiki;

use Biz\model\brand\Brand;
use Biz\service\esSearch\Wiki as esWiki;
use Doraemon\cache\MultiContent\SearchRecommend;
use Doraemon\cache\Search\ListInWikiClassify as cListInWikiClassify;
use Doraemon\model\Elasticsearch\EsWikiListModel;
use Doraemon\pockets\config\IniConfig;
use Doraemon\pockets\constInterface\ABTest\MarkManage;
use Doraemon\service\ABTest\GetTestStrategy as sGetTestStrategy;
use Doraemon\tools\IdParse;
use Doraemon\tools\Curl;
use Doraemon\tools\HhzClient;
use GuzzleHttp\RequestOptions;
use function Clue\StreamFilter\append;

class Schedule
{
    const SORT_TYPE_HOT = 0;
    const SORT_TYPE_TIME = 1;

    const BRAND_SCORE_WEIGHT = [
        Brand::BRAND_TYPE_SUPER => 1.06, // 超级品牌权重
        Brand::BRAND_TYPE_BEST => 1.05, // 精选品牌权重
        Brand::BRAND_TYPE_COMMON => 1.03, // 认证品牌权重
    ];

    const TIME_WEIGHT = 25; // 时间权重

    const GOODS_HOT_WEIGHT = 100; // 商品热度权重

    const RELATE_CONTENT_WEIGHT = 10; // 累计住友内容

    const SAVE_MAX_PAGE = 30;

    private static $wikiClassifyKey = "";
    private static $wikiUidClassifyKey = "";

    const PAGESIZE = 20;

    // 获取当前时间戳 第一页的时间 应该和 第十页的时间相同
    public static function getCurrentTime($page, $uid, $categoryId)
    {
        if ($page == 1) {
            $currentTime = time();
            SearchRecommend::setCurrentTime($uid, $currentTime, $categoryId);
        } else {
            $currentTime = (int)SearchRecommend::getCurrentTime($uid, $categoryId);
            $currentTime = $currentTime ? $currentTime : time();
        }

        return $currentTime;
    }

    // 获取wiki类列表
    public static function getCategoryLisyOrder(&$where, $currentTime)
    {
        $scriptString = "double score = (Math.log(181 - Math.min(180, ({$currentTime} - doc['obj_last_relate_time'].value) / 86400)) / Math.log(181)) * " . self::TIME_WEIGHT . "   + (Math.log(1 + Math.min(100, doc['relate_num'].value)) / Math.log(101)) * " . self::RELATE_CONTENT_WEIGHT . " + (Math.log(1 + Math.min(1000, doc['basic_goods_hot'].value)) / Math.log(1001)) * " . self::GOODS_HOT_WEIGHT . ";if(doc['brand_type'].value == " . Brand::BRAND_TYPE_SUPER . ") {score = score * " . self::BRAND_SCORE_WEIGHT[Brand::BRAND_TYPE_SUPER] . ";}if(doc['brand_type'].value == " . Brand::BRAND_TYPE_BEST . ") {score = score * " . self::BRAND_SCORE_WEIGHT[Brand::BRAND_TYPE_BEST] . ";}if(doc['brand_type'].value == " . Brand::BRAND_TYPE_COMMON . ") {score = score * " . self::BRAND_SCORE_WEIGHT[Brand::BRAND_TYPE_COMMON] . ";}return score;";

        $where["ORDER"] = array(
            // 策略权重
            array(
                "_script" => array(
                    "type" => "number",
                    "order" => "desc",
                    "script" => array(
                        "lang" => "painless",
                        "source" => $scriptString
                    )
                )
            ),
            // 二次排序用时间
            array(
                "addtime" => "desc"
            )
        );
    }

    // 基于算法ctr预估重排序
    public static function reScoreWithCtrAi($hashIdWeightData)
    {
        if (!(is_array($hashIdWeightData) && $hashIdWeightData)) {
            return array();
        }

        $config = IniConfig::getConfigSelect('search', 'wiki_price_rescore');
        $wikiPriceRescoreHost = $config['host'];

        $objList = array_keys($hashIdWeightData);

        $objList = array_map("strval", $objList);

        Curl::$defaultConfig[RequestOptions::TIMEOUT] = 0.5;
        $res = Curl::Request('GET', $wikiPriceRescoreHost . "?uid=" . HhzClient::getUid() . "&obj_list=" . urlencode(json_encode($objList)));

        if (!(($res['json']['code'] == 1) && is_array($res['json']['data']) && $res['json']['data'] && isset($res['json']['data']['content_list'])
            && is_array($res['json']['data']['content_list']) && $res['json']['data']['content_list'])) {
            return array_keys($hashIdWeightData);
        }

        Curl::$defaultConfig[RequestOptions::TIMEOUT] = 3;

        $rescores = $res['json']['data']["content_list"];

        $originWeightMap = array();
        foreach ($objList as $key => $objId) {
            $originWeightMap[$objId] = $rescores[$key];
        }

        arsort($originWeightMap);
        return array_keys($originWeightMap);
    }

    public static function handleWikiUser($where, $sortType, $page, $pageSize)
    {
        if (cListInWikiClassify::SearchWIkiExist(self::getSeeKey())) {
            $hashIdWeights = cListInWikiClassify::getIdWeightData(self::getSeeKey());
            $hashIdWeights = is_array($hashIdWeights) && $hashIdWeights ? $hashIdWeights : array();

            // 取出的内容为空 由于主从缓存删除key有延迟 重新生成值
            if (empty($hashIdWeights)) {
                $hashIdWeightData = self::buildArticleInfos($where, $sortType, $page, $pageSize);
            } else {
                $filterHashIdWeights = array_filter($hashIdWeights);
                // 使用过滤的数据进行下面的操作
                $hashIdWeightData = $filterHashIdWeights;
            }
        } else {
            // key不存在开始生成缓存 生成好物分类频道内容
            $hashIdWeightData = self::buildArticleInfos($where, $sortType, $page, $pageSize);
        }

        list($searchIds, $is_over) = self::handleWikiCtr($page, $pageSize, $hashIdWeightData);
        return array($searchIds, $is_over);
    }

    public static function handleWikiCtr($page, $pageSize, $hashIdWeightData)
    {
        $is_over = 1;
        $searchIds = array();
        $allSearchIds = self::reScoreWithCtrAi($hashIdWeightData);

        if (is_array($allSearchIds) && $allSearchIds) {
            // 重新计算偏移量
            list($offsetStart, $offsetEnd) = self::getOffset($page, $pageSize);
            $allSearchIds = array_filter($allSearchIds);
            $cacheData = array();

            $offset = $offsetStart;
            foreach ($allSearchIds as $id) {
                $cacheData[$id] = $offset;
                $offset++;
            }

            if (is_array($cacheData) && $cacheData) {
                // 设置查询缓存
                cListInWikiClassify::addData(self::getUidSeeKey(), $cacheData);
            }

            $searchIds = array_slice($allSearchIds, $offsetStart, $pageSize);

            if (count($searchIds) >= $pageSize) {
                $is_over = 0;
            }
        } else {
            // 当获取不到值时 设置key为空 缓存时间内不再查数据 减少查询次数
            cListInWikiClassify::setSearchWikiUidForEmpty(self::getUidSeeKey());
        }

        return array(
            $searchIds, $is_over
        );
    }

    public static function buildArticleInfos($where, $sortType, $page, $pageSize)
    {
        $resetPage = intval(($page - 1) / self::SAVE_MAX_PAGE) + 1;
//        $result = esWiki::getListForClassify($where, esWiki::SCENES_APP_CATEGORY_LIST, $sortType, $resetPage, self::SAVE_MAX_PAGE * $pageSize);
        $result = EsWikiListModel::getList($where, EsWikiListModel::SCENES_APP_CATEGORY_LIST, $sortType, $resetPage, self::SAVE_MAX_PAGE * $pageSize);
        $hashIdWeight = array();
        if (is_array($result["rows"]) && $result["rows"]) {
            foreach ($result["rows"] as $item) {
                $hashIdWeight[$item["id"]] = $item["weight"];
            }

            if (is_array($hashIdWeight) && $hashIdWeight) {
                // 设置查询缓存
                cListInWikiClassify::setIdWeightData(self::getSeeKey(), $hashIdWeight);
            }
        } else {
            // 当获取不到值时 设置key为空 缓存时间内不再查数据 减少查询次数
            $hashIdWeight = array(
                0 => 0
            );
            cListInWikiClassify::setIdWeightData(self::getSeeKey(), $hashIdWeight);
        }

        return $hashIdWeight;
    }

//    public static function buildArticleInfos2($where, $sortType, $page, $pageSize)
//    {
//        $is_over = 1;
//        $searchIds = array();
//
//        $resetPage = intval(($page - 1)/ self::SAVE_MAX_PAGE) + 1;
//
//        $result = esWiki::getListForClassify($where, esWiki::SCENES_APP_CATEGORY_LIST, $sortType, $resetPage, self::SAVE_MAX_PAGE * self::PAGESIZE);
//
//        $allSearchIds = self::reScoreWithCtrAi($result["rows"]);
//
//        if (is_array($allSearchIds) && $allSearchIds) {
//            // 重新计算偏移量
//            list($offsetStart, $offsetEnd) = self::getOffset($page, $pageSize);
//            $allSearchIds = array_filter($allSearchIds);
//            $cacheData = array();
//
//            $offset = $offsetStart;
//            foreach ($allSearchIds as $id) {
//                $cacheData[$id["id"]] = $offset;
//                $offset++;
//            }
//
//            if (is_array($cacheData) && $cacheData) {
//                // 设置查询缓存
//                cListInWikiClassify::addData(self::getSeeKey(), $cacheData);
//            }
//
//            $searchIds = array_slice($allSearchIds, $offsetStart, $pageSize);
//
//            if (count($searchIds) >= $pageSize) {
//                $is_over = 0;
//            }
//        } else {
//            // 当获取不到值时 设置key为空 缓存时间内不再查数据 减少查询次数
//            cListInWikiClassify::setSearchKeyForEmpty(self::getSeeKey());
//        }
//
//        return array(
//            $searchIds, $is_over
//        );
//    }

    // 好物分类频道 调度
    public static function searchForCategoryLisy(array $where = [], $sortType = 0, $page = 1, $categoryId, $pageSize = self::PAGESIZE)
    {
        self::setUidSeeKey($page, $categoryId, HhzClient::getUid(), $where);
        self::setSeeKey($page, $categoryId, $where);

        $isOver = 1;
        // 判断搜索内容key存不存在
        if (cListInWikiClassify::SearchWikiUidExist(self::getUidSeeKey())) {
            list($offsetStart, $offsetEnd) = self::getOffset($page, $pageSize);
            $searchIds = cListInWikiClassify::getData(self::getUidSeeKey(), $offsetStart, $offsetEnd);
            $searchIds = is_array($searchIds) && $searchIds ? $searchIds : array();

            // 取出的内容为空 由于主从缓存删除key有延迟 重新生成值
            if (empty($searchIds)) {
                list($searchIds, $isOver) = self::handleWikiUser($where, $sortType, $page, $pageSize);
            } else {
                $filterSearchIds = array_filter($searchIds);
                if (is_array($filterSearchIds) && $filterSearchIds) {
                    // 用原始的数据进行判断是否没有数据了
                    if (count($searchIds) >= $pageSize) {
                        $isOver = 0;
                    }
                }
                // 使用过滤的数据进行下面的操作
                $searchIds = $filterSearchIds;
            }
        } else {
            // key不存在开始生成缓存 生成好物分类频道内容
            list($searchIds, $isOver) = self::handleWikiUser($where, $sortType, $page, $pageSize);
        }

        // 构建 即时兴趣
        // 对功能进行ab test
        $strategy = sGetTestStrategy::getStrategyByTestId(MarkManage::HAOHAOZHUSSX_5_23);
        if ($strategy == 2) {
            $instantInterestContents = self::getInstantInterestContent($categoryId);
            if (is_array($instantInterestContents) && $instantInterestContents) {
                $searchIds = self::insertInterestData($searchIds, $instantInterestContents);
            }
        }

        $return = ['total' => count($searchIds), 'is_over' => $isOver, 'rows' => $searchIds];

        return $return;
    }

    // 将 即时兴趣 的内容 插入 原始内容 中
    public static function insertInterestData($searchIds, $instantInterestContents)
    {
        $internalNum = 5;
        $returnData = array();

        $interestContentsDiff = array_diff($instantInterestContents, $searchIds);

        foreach( $searchIds as $index => $searchId) {
            array_push($returnData, $searchId);

            if ((($index + 1) % $internalNum == 0) && count($interestContentsDiff) > 0) {
                array_push($returnData, array_shift($interestContentsDiff));
            }
        }

        return $returnData;
    }

    // 构建 即时兴趣
    public static function getInstantInterestContent($categoryId)
    {
        $config = IniConfig::getConfigSelect('search', 'wiki_instant_interest');
        $wikiInstantInterestHost = $config['host'];

        Curl::$defaultConfig[RequestOptions::TIMEOUT] = 0.2;
        $res = Curl::Request('GET', $wikiInstantInterestHost."?uid=".HhzClient::getUid()."&cate_id=".$categoryId);

        if (!(($res['json']['code'] == 1) && is_array($res['json']['data']) && $res['json']['data'] && isset($res['json']['data']['content_list'])
            && is_array($res['json']['data']['content_list']) && $res['json']['data']['content_list'])){
            return array();
        }

        Curl::$defaultConfig[RequestOptions::TIMEOUT] = 3;

        $contentList = $res['json']['data']['content_list'];

        return $contentList;
    }

    // 获取好物分类频道 缓存偏移量
    public static function getOffset($page, $pageSize)
    {
        $showPageSize = $pageSize;
        $resetPage = ($page - 1) % self::SAVE_MAX_PAGE;
        $start = ($resetPage) * $showPageSize;
        $end = $start + $showPageSize - 1;

        return array(
            $start,
            $end
        );
    }

    // 设置好物分类频道 搜索缓存 uid key
    public static function setUidSeeKey($page, $categoryId, $uid, $where)
    {
        $savePageKey = (int)(($page - 1) / self::SAVE_MAX_PAGE) + 1;

        $saveCacheKey = $categoryId . "-" . $uid . "-" . $savePageKey . "-" . md5(json_encode($where));
        //去掉ab test
        /*
        // 对ctr功能进行ab test
        $strategy = sGetTestStrategy::getStrategyByTestId(MarkManage::WIKI_CTR_IN_GOODS);

        // 分桶A
        if ($strategy == 2) {
            $saveCacheKey = $saveCacheKey ."-A";
        } else if ($strategy == 3) {
            // 分桶B
            $saveCacheKey = $saveCacheKey ."-B";
        } else if ($strategy == 4) {
            // 分桶B
            $saveCacheKey = $saveCacheKey ."-C";
        }*/

        $saveCacheKey = $saveCacheKey . "-A";

        self::$wikiUidClassifyKey = $saveCacheKey;
    }

    // 获取好物分类频道 搜索缓存 uid key
    public static function getUidSeeKey()
    {
        return self::$wikiUidClassifyKey;
    }

    // 设置好物分类频道 搜索缓存 uid key
    public static function setSeeKey($page, $categoryId, $where)
    {
        $savePageKey = (int)(($page - 1) / self::SAVE_MAX_PAGE) + 1;
        $saveCacheKey = $categoryId . "-" . $savePageKey . "-" . md5(json_encode($where));

        self::$wikiClassifyKey = $saveCacheKey;
    }

    // 获取好物分类频道 搜索缓存 uid key
    public static function getSeeKey()
    {
        return self::$wikiClassifyKey;
    }
}